#ifndef _MPxShaderOverride
#define _MPxShaderOverride
//-
// ==========================================================================
// Copyright (C) 2010 Autodesk, Inc., and/or its licensors.  All
// rights reserved.
//
// The coded instructions, statements, computer programs, and/or related
// material (collectively the "Data") in these files contain unpublished
// information proprietary to Autodesk, Inc. ("Autodesk") and/or its
// licensors,  which is protected by U.S. and Canadian federal copyright law
// and by international treaties.
//
// The Data may not be disclosed or distributed to third parties or be
// copied or duplicated, in whole or in part, without the prior written
// consent of Autodesk.
//
// The copyright notices in the Software and this entire statement,
// including the above license grant, this restriction and the following
// disclaimer, must be included in all copies of the Software, in whole
// or in part, and all derivative works of the Software, unless such copies
// or derivative works are solely in the form of machine-executable object
// code generated by a source language processor.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
// AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED
// WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF
// NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE,
// OR ARISING FROM A COURSE OF DEALING, USAGE, OR TRADE PRACTICE. IN NO
// EVENT WILL AUTODESK AND/OR ITS LICENSORS BE LIABLE FOR ANY LOST
// REVENUES, DATA, OR PROFITS, OR SPECIAL, DIRECT, INDIRECT, OR
// CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK AND/OR ITS LICENSORS HAS
// BEEN ADVISED OF THE POSSIBILITY OR PROBABILITY OF SUCH DAMAGES.
// ==========================================================================
//+
//
// CLASS: MPxShaderOverride
//
// ****************************************************************************
//
// CLASS DESCRIPTION (MPxShaderOverride)
//
//  MPxShaderOverride allows the user to create a custom draw override
//  for associating a full shading effect with a shading node (custom or
//  standard) in Maya. Its primary use is for associating hardware effects
//  with pre-existing plugin software shaders.
//
// ****************************************************************************

#if defined __cplusplus

// ****************************************************************************
// INCLUDED HEADER FILES

#include <maya/MStatus.h>
#include <maya/MHWGeometry.h>

// ****************************************************************************
// DECLARATIONS

class MObject;
class MString;

// ****************************************************************************
// NAMESPACE

namespace MHWRender
{

class MDrawContext;
class MRenderItemList;

// ****************************************************************************
// CLASS DECLARATION (MPxShaderOverride)

//! \ingroup OpenMayaRender MPx
//! \brief Base class for user defined shading effect draw overrides.
/*!
MPxShaderOverride allows the user to create a custom override for
associating a "full shading effect" with a shading node (custom or standard)
in Maya. Its primary use is for associating hardware effects with pre-existing
plugin software shaders.

A "full shading effect" defines the complete shading and lighting involved
to render a given object. Input resources for shading such as geometry,
textures, and lights are defined and bound to the shading effect via the
override as required. The override is fully responsible for these tasks.

As an example, for hardware shading, this can be thought of as implementing
a CgFx or HLSL effect file renderer which can use the resources defined within
a Maya scene.

There are three main phases that the override must implement:

1) Initialization Phase : This phase occurs when Maya determines that the
hardware shader generated through this override needs to be rebuilt. This may
be due to a new object using the shader, or because something has changed on
the shader that requires a complete rebuild. During the initialization phase the
geometric stream requirements can be specified using addGeometryRequirement().
The requirements will determine which geometric streams are required from
objects to which the given shading effect is assigned. If no requirements are
specified then a single position stream requirement will be used.

The initialize() method must return a string representing the shader
key.  It often happens that different instances of the
MPxShaderOverride represent essentially the same shader, but with
different shader parameters. The shader key is used to identify the
MPxShaderOverride instances representing the same shader. To optimize
rendering, the Viewport 2.0 will make an effort to regroup the
rendering of objects with the same MPxShaderOverride shader key. This
allows the plug-in to perform its setup only once for the entire
sequence. It is up to each plug-in to decide what the meaning of
representing the same shader is.

2) Data Update Phase : In this phase, updating of all data values required for
shading is performed. The interface has an explicit split of when the dependency
graph can be accessed (updateDG()), and when the draw API (e.g. OpenGL) can be
accessed (updateDevice()). Any intermediate data can be cleaned up when
endUpdate() is called.

As an example the override may require input from an attribute on a given node.
- updateDG() would evaluate the plug for the attribute and cache its value
temporarily on the override.
- updateDevice() would take the temporarily cached value and bind it to a
shader stored on the graphic device.
- endUpdate() would reset the temporary data on the override.

Note that the override can provide a draw hint as to whether shading will
involve semi-transparency. This hint can be provided by overriding the
isTransparent() method which gets called between updateDevice() and
endUpdate().

3) Drawing Phase : The actual drawing using the shader is performed in the
pure virtual draw() method. The callback method should return true if it was
able to draw successfully. If false is returned then drawing will be done
using the default shader used for unsupported materials.

Drawing is explicitly not intermixed with the data update on purpose. By the
time draw is being called all evaluation should have been completed. If there
is user data that needs to be passed between the update and drawing phases
the override must cache that data itself. It is an error to access the Maya
dependency graph during draw and attempts to do so may result in instability.

Although it is possible for implementations of the draw() method to handle all
shader setup and geometry draw, the expected use of the draw() method is to do
shader setup only. Then drawGeometry() can be called to allow Maya to handle
the actual geometry drawing. If manual geometry binding is required however, it
is possible to query the hardware resource handles through the geometry on each
render item in the render item list passed into the draw() method.

The activateKey() and terminateKey() method will also be invoked in
the draw phase each time a render item is drawn with a different
shader key (see the discussion above about shader keys). The
activateKey() and terminateKey() methods can be used to optimize
rendering by configuring the rendering state only once for a batch of
draw() calls that are sharing the same shader key.

The sequence of invocations will look like:
  - shaderOverrideA->activateKey(...)
  - shaderOverrideA->draw(...)
  - shaderOverrideB->draw(...)
  - shaderOverrideC->draw(...)
  - ...
  - shaderOverrideA->terminateKey(...)
  - shaderOverrideX->activateKey(...)
Note that the terminateKey() callback is always invoked on the same
MPxShaderOverride instance as the one used to invoked the
activateKey() callback.

Note if full draw control is desired, the proxy class MPxDrawOverride may be
more appropriate.

Implementations of MPxShaderOverride must be registered with Maya through
MDrawRegistry.
*/
class OPENMAYARENDER_EXPORT MPxShaderOverride
{
public:
	MPxShaderOverride(const MObject& obj);
	virtual ~MPxShaderOverride();

	// 1) Initialize phase
	virtual MString initialize(MObject object) = 0;
    
	// 2) Update phase
	virtual void updateDG(MObject object);
	virtual void updateDevice();
	virtual void endUpdate();

	// 3) Draw phase
    virtual void activateKey(MDrawContext& context);
	virtual bool draw(
		MDrawContext& context,
		const MRenderItemList& renderItemList) const = 0;
    virtual void terminateKey(MDrawContext& context);

	// Override properties
	virtual bool isTransparent();
	virtual bool overridesDrawState();
	virtual bool rebuildAlways();

	static const char* className();

protected:
	// Protected helper methods for use by derived classes
	MStatus addGeometryRequirement(const MVertexBufferDescriptor& desc);
	void drawGeometry(const MDrawContext& context) const;

private:
	// Internal data
	void setInternalData( void * data ) { fData = data; }
	void *fData;
	bool fInInit;

};

} // namespace MHWRender

#endif /* __cplusplus */
#endif /* _MPxShaderOverride */
